package dyncall

/*
#include "../c/dyncall/dyncall.h"
#include "bridge/_bridge_.h"
#cgo LDFLAGS: -L${SRCDIR}/ -ldyncall
*/
import "C"
import (
	"gitee.com/yonoz/go_dyncall/model"
	"runtime"
	"unsafe"
)

type DCCallVM struct {
	vm   *C.DCCallVM
	free bool
}
type DCStruct struct {
	structPointer *C.DCstruct
	free          bool
}

//go:generate go run ../install/main.go ${CC} -O0 -c bridge/_bridge_.S -o ./dyncall
func DcNewCallVM(size int) *DCCallVM {

	vm := C.dcNewCallVM(C.DCsize(size))
	if vm == nil {
		return nil
	}
	result := &DCCallVM{vm: vm}
	runtime.SetFinalizer(result, DcFree)
	return result
}
func DcFree(vm *DCCallVM) {
	if vm == nil || vm.vm == nil || vm.free {
		return
	}
	vm.free = true
	C.dcFree(vm.vm)
}

func DcReset(vm *DCCallVM) {
	if vm == nil || vm.vm == nil || vm.free {
		return
	}
	C.dcReset(vm.vm)
}
func DcMode(vm *DCCallVM, mode int) {
	if vm == nil || vm.vm == nil || vm.free {
		return
	}
	C.dcMode(vm.vm, C.DCint(mode))
}
func DcArgBool(vm *DCCallVM, arg bool) {
	if vm == nil || vm.vm == nil || vm.free {
		return
	}
	var intArg int
	if arg {
		intArg = 1
	} else {
		intArg = 0
	}
	C.dcArgBool(vm.vm, C.DCbool(intArg))
}
func DcArgChar(vm *DCCallVM, arg rune) {
	if vm == nil || vm.vm == nil || vm.free {
		return
	}
	C.dcArgChar(vm.vm, C.DCchar(arg))
}
func DcArgShort(vm *DCCallVM, arg int16) {
	if vm == nil || vm.vm == nil || vm.free {
		return
	}
	C.dcArgShort(vm.vm, C.DCshort(arg))
}
func DcArgInt(vm *DCCallVM, arg int32) {
	if vm == nil || vm.vm == nil || vm.free {
		return
	}
	C.dcArgInt(vm.vm, C.DCint(arg))
}
func DcArgLong(vm *DCCallVM, arg int64) {
	if vm == nil || vm.vm == nil || vm.free {
		return
	}
	C.dcArgLong(vm.vm, C.DClong(arg))
}

//func dcArgLongLong(vm *DCCallVM, arg  int) {
//	if vm == nil || vm.vm == nil || vm.free {
//		return
//	}
//	C.dcArgLong(vm.vm, C.DClonglong(arg))
//}

func DcArgFloat(vm *DCCallVM, arg float32) {
	if vm == nil || vm.vm == nil || vm.free {
		return
	}
	C.dcArgFloat(vm.vm, C.DCfloat(arg))
}
func DcArgDouble(vm *DCCallVM, arg float64) {
	if vm == nil || vm.vm == nil || vm.free {
		return
	}
	C.dcArgDouble(vm.vm, C.DCdouble(arg))
}

func DcArgPointer(vm *DCCallVM, arg unsafe.Pointer) {
	if vm == nil || vm.vm == nil || vm.free {
		return
	}
	C.dcArgPointer(vm.vm, C.DCpointer(arg))
}

func DcArgStruct(vm *DCCallVM, dcStruct *DCStruct, arg unsafe.Pointer) {
	if vm == nil || vm.vm == nil || vm.free || dcStruct == nil || dcStruct.free {
		return
	}
	C.dcArgStruct(vm.vm, dcStruct.structPointer, C.DCpointer(arg))
}

func DcCallVoid(vm *DCCallVM, pointer model.Pointer) {
	if vm == nil || vm.vm == nil || vm.free || pointer == nil || pointer.GetPointer() == nil {
		return
	}
	C.dcCallVoid(vm.vm, C.DCpointer(pointer.GetPointer()))
}
func DcCallBool(vm *DCCallVM, pointer model.Pointer) bool {
	if vm == nil || vm.vm == nil || vm.free || pointer == nil || pointer.GetPointer() == nil {
		return false
	}
	value := C.dcCallBool(vm.vm, C.DCpointer(pointer.GetPointer()))
	if int(value) == 0 {
		return false
	}
	return true
}
func DcCallChar(vm *DCCallVM, pointer model.Pointer) rune {
	if vm == nil || vm.vm == nil || vm.free || pointer == nil || pointer.GetPointer() == nil {
		return 0
	}
	value := C.dcCallChar(vm.vm, C.DCpointer(pointer.GetPointer()))
	return rune(value)
}
func DcCallShort(vm *DCCallVM, pointer model.Pointer) int16 {
	if vm == nil || vm.vm == nil || vm.free || pointer == nil || pointer.GetPointer() == nil {
		return 0
	}
	value := C.dcCallShort(vm.vm, C.DCpointer(pointer.GetPointer()))
	return int16(value)
}

func DcCallInt(vm *DCCallVM, pointer model.Pointer) int32 {
	if vm == nil || vm.vm == nil || vm.free || pointer == nil || pointer.GetPointer() == nil {
		return 0
	}
	value := C.dcCallInt(vm.vm, C.DCpointer(pointer.GetPointer()))
	return int32(value)
}
func DcCallLong(vm *DCCallVM, pointer model.Pointer) int64 {
	if vm == nil || vm.vm == nil || vm.free || pointer == nil || pointer.GetPointer() == nil {
		return 0
	}
	value := C.dcCallLong(vm.vm, C.DCpointer(pointer.GetPointer()))
	return int64(value)
}

func DcCallLongLong(vm *DCCallVM, pointer model.Pointer) int64 {
	if vm == nil || vm.vm == nil || vm.free || pointer == nil || pointer.GetPointer() == nil {
		return 0
	}
	value := C.dcCallLongLong(vm.vm, C.DCpointer(pointer.GetPointer()))
	return int64(value)
}
func DcCallFloat(vm *DCCallVM, pointer model.Pointer) float32 {
	if vm == nil || vm.vm == nil || vm.free || pointer == nil || pointer.GetPointer() == nil {
		return 0
	}
	value := C.dcCallFloat(vm.vm, C.DCpointer(pointer.GetPointer()))
	return float32(value)
}
func DcCallDouble(vm *DCCallVM, pointer model.Pointer) float64 {
	if vm == nil || vm.vm == nil || vm.free || pointer == nil || pointer.GetPointer() == nil {
		return 0
	}
	value := C.dcCallDouble(vm.vm, C.DCpointer(pointer.GetPointer()))
	return float64(value)
}
func DcCallPointer(vm *DCCallVM, pointer model.Pointer) unsafe.Pointer {
	if vm == nil || vm.vm == nil || vm.free || pointer == nil || pointer.GetPointer() == nil {
		return nil
	}
	value := C.dcCallPointer(vm.vm, C.DCpointer(pointer.GetPointer()))
	return unsafe.Pointer(value)
}

func dcCallStruct(vm *DCCallVM, pointer model.Pointer, dcStruct *DCStruct, structPointer unsafe.Pointer) {
	if vm == nil || vm.vm == nil || vm.free || pointer == nil || pointer.GetPointer() == nil || dcStruct == nil || dcStruct.free {
		return
	}
	C.dcCallStruct(vm.vm, C.DCpointer(pointer.GetPointer()), dcStruct.structPointer, C.DCpointer(structPointer))
}

func DcCallString(vm *DCCallVM, pointer model.Pointer) string {
	if vm == nil || vm.vm == nil || vm.free || pointer == nil || pointer.GetPointer() == nil {
		return ""
	}
	value := C.dcCallPointer(vm.vm, C.DCpointer(pointer.GetPointer()))
	return C.GoString((*C.char)(value))
}

func DcGetError(vm *DCCallVM) int32 {
	if vm == nil || vm.vm == nil || vm.free {
		return 0
	}
	value := C.dcGetError(vm.vm)
	return int32(value)
}
func DcNewStruct(fieldCount int, alignment int) *DCStruct {
	value :=
		&DCStruct{
			structPointer: C.dcNewStruct(C.DCsize(fieldCount), C.DCint(alignment)),
		}
	runtime.SetFinalizer(value, DcFreeStruct)
	return value
}
func DcStructField(dcStruct *DCStruct, filedType int, alignment int, arrayLength int) {
	if dcStruct == nil || dcStruct.free {
		return
	}
	C.dcStructField(dcStruct.structPointer, C.DCint(filedType), C.DCint(alignment), C.DCsize(arrayLength))
}
func DcSubStruct(dcStruct *DCStruct, fieldCount int, alignment int, arrayLength int) {
	if dcStruct == nil || dcStruct.free {
		return
	}
	C.dcSubStruct(dcStruct.structPointer, C.DCsize(fieldCount), C.DCint(alignment), C.DCsize(arrayLength))
}
func DcCloseStruct(dcStruct *DCStruct, fieldCount int, alignment int, arrayLength int) {
	if dcStruct == nil || dcStruct.free {
		return
	}
	C.dcCloseStruct(dcStruct.structPointer)
}
func DcStructSize(dcStruct *DCStruct) int {
	if dcStruct == nil || dcStruct.free {
		return 0
	}
	return int(C.dcStructSize(dcStruct.structPointer))
}
func DcStructAlignment(dcStruct *DCStruct) int {
	if dcStruct == nil || dcStruct.free {
		return 0
	}
	return int(C.dcStructAlignment(dcStruct.structPointer))
}
func DcFreeStruct(dcStruct *DCStruct) {
	if dcStruct == nil || dcStruct.free {
		return
	}
	dcStruct.free = true
	C.dcFreeStruct(dcStruct.structPointer)
}
func DcDefineStruct(signature string) *DCStruct {
	value :=
		&DCStruct{
			structPointer: C.dcDefineStruct(C.CString(signature)),
		}
	runtime.SetFinalizer(value, DcFreeStruct)
	return value
}
